ひとりNavigation API Advent Calendar 23日目
https://gyazo.com/56c1f68c32b26e881a575fe5456d0171
これはひとりNavigation API Advent Calendarの23日目です。
今日はSPAにまつわる策定中のWeb APIであるSoft Navigation Heuristicsについてを深ぼっていきます
Soft Navigation Heuristicsとは何?
URLは変わらずDOMだけが書き換わるSPAの「同一文書内の遷移」をブラウザが検出するための仕組み
従来のブラウザはSPAの画面遷移を「ナビゲーション」と認識できず、パフォーマンス計測が困難だった問題がある
それを解決するために提案されているもの
ブラウザは以下の条件を満たすとSoft Navigationと判断する
ユーザー操作(クリック・キーボードなど)に起因するタスクの子孫であること
そのユーザー操作に起因してDOM Nodeが追加されること
同一文書内でのコミット(History APIやNavigation API)が発生すること
追加された要素によるContentful Paintが発生すること
これらを総合して「ユーザー操作による画面遷移」と推定する
ユーザー操作 → Context の伝播 → DOM 変更 → Contentful Paint → URL 変更
Soft Navigationを正しく検出するためには、「どのタスクがどのタスクを生んだか」という因果関係を追跡する必要がある
以下の仕組みを使う
AsyncContext API(TC39で提案中)
https://github.com/tc39/proposal-async-context
現在Stage 2とのこと
ChromiumのTask Attribution v2
Soft Navigationを検出するために、以下の仕様にフックを追加
HTML のEvent dispatch
History APIの更新
DOM Nodeの挿入処理
Largest Contentful Paint(LCP)
これにより Soft Navigation発生時に paint タイミングをリセットし、SPA の画面遷移を正しく計測できるようにする
現在はChromiumのみでしか実装されていない
Chrome.icon chrome://flags/#soft-navigation-heuristicsフラグで使用解除
Microsoft Edge.icon edge://flags/#soft-navigation-heuristicsフラグで使用解除
計測方法
SoftNavigationEntryを監視して、「いつソフトナビゲーションが発生したか」を取得する
code:js
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
console.log('Layout Shift time:', entry);
}
}).observe({type: 'layout-shift', buffered: true, includeSoftNavigationObservations: true});
フラグを解除し、このCosenseでコンソールで実行すると確認できる
https://gyazo.com/e43559491b9053462fd1ba70d0c18106
ページロード後に、すでに発生したSoftNavigationEntryを取得する
code:js
const softNavs = performance.getEntriesByType("soft-navigation");
SoftNavigationEntry、InteractionContentfulPaintを関連付けて、「そのナビゲーションに対するLCP相当の時間」を計算する例
code:js
const softNavs = [];
const observer = new PerformanceObserver((list) => {
// Soft Navigation の記録
for (const navEntry of list.getEntriesByType("soft-navigation")) {
softNavs.push(navEntry);
}
// Interaction Contentful Paint の処理
for (const icpEntry of list.getEntriesByType("interaction-contentful-paint")) {
const navEntry = softNavs.find(
(nav) => nav.navigationId === icpEntry.navigationId
);
if (navEntry) {
const relative = icpEntry.startTime - navEntry.startTime;
console.log("Soft Navigation LCP-like timing:", relative);
}
}
});
observer.observe({
type: "soft-navigation",
includeSoftNavigationObservations: true,
buffered: true,
});
observer.observe({
type: "interaction-contentful-paint",
includeSoftNavigationObservations: true,
buffered: true,
});
WPT
https://wpt.fyi/results/soft-navigation-heuristics?label=experimental&label=master&aligned
https://wpt.fyi/results/soft-navigation-heuristics?label=stable&label=master&aligned
Edgeでは安定して使える…?
このWeb APIはNavigation APIに依存すべきものか?
結論としてはNO
Navigation APIは、同一ドキュメント内の履歴遷移を開始したり観測したりするための多くのメソッドを統合しています。また、<a href>のクリックや<form action>の送信といった「意味的なナビゲーション」をintercept()でフックし、カスタム動作を提供する仕組みがある
しかし、Soft Navigation APIの計測がこのintercept()機能の利用を前提としてしまうと、
将来のWebアプリにしか対応できない(History APIのものは使えなくなる)
あるいは 既存のアプリがルーティングライブラリを全面的に書き換える必要がある
といった問題が生じる
これは「大規模に計測できるようにする」という本来の目的に反する
Navigation API は 「本当のナビゲーション」と「単なるインタラクション」 を区別しない
そのため、同一ドキュメント内の履歴変更を観測するには役立つものの、Soft Navigation を検出するには 追加のヒューリスティック性が必要となる
関連情報
Soft Navigations
GitHub - WICG/soft-navigations: Heuristics to detect Single Page Apps soft navigations
Soft navigation heuristics - Google Docs
SoftNavigation performance entry - Chrome Platform Status
新しいソフト ナビゲーションのオリジン トライアル | Blog | Chrome for Developers
ソフト ナビゲーションの測定実験 | Web Platform | Chrome for Developers
Web の仕様を眺めるシリーズ Soft Navigations Performance Entry | Offers Tech Blog
ソフトナビゲーションの仕組みと使い方 | yossy.dev
Web サイトのパフォーマンスを計測するためのタイミング関係の API について | blog.bokken.io